package com.example.Service;

import com.example.WebSocket.AsrWebSocketClient;
import com.example.utils.VivoAuth;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 调用asr接口
 * 语音转文字的主要方法
 * 通过分批次将长语音发送和50帧数的容错，解决长语音的识别
 */
@Service
public class AsrService {

    private static final String APP_ID = "2025985389";
    private static final String APP_KEY = "eAkRKtYXOawsmtVv";
    private static final String URI_PATH = "/asr/v2";
    private static final String METHOD = "GET";
    private static final int SAMPLE_RATE = 16000; // 采样率
    private static final int BITS_PER_SAMPLE = 16; // 每个样本的位数
    private static final int BYTES_PER_SECOND = SAMPLE_RATE * BITS_PER_SAMPLE / 8; // 每秒的字节数
    private static final int MAX_FRAMES_PER_SEGMENT = 750; // 每个段的最大帧数
    private static final int OVERLAP_FRAMES = 50; // 重叠帧数，用于保持连续性

    public String processAudio(byte[] pcmData) throws UnsupportedEncodingException, InterruptedException {
        int frameSize = 1280; // 40毫秒帧长
        int totalFrames = (int) Math.ceil(pcmData.length / (double) frameSize);
        
        if (totalFrames <= MAX_FRAMES_PER_SEGMENT) {
            return processSingleAudioSegment(pcmData);
        } else {
            return processLongAudio(pcmData, frameSize, totalFrames);
        }
    }

    private String processLongAudio(byte[] pcmData, int frameSize, int totalFrames) throws UnsupportedEncodingException, InterruptedException {
        int segments = (int) Math.ceil(totalFrames / (double) (MAX_FRAMES_PER_SEGMENT - OVERLAP_FRAMES));
        StringBuilder finalResult = new StringBuilder();
        String lastSegmentResult = null;
        
        for (int i = 0; i < segments; i++) {
            int startFrame = i * (MAX_FRAMES_PER_SEGMENT - OVERLAP_FRAMES);
            int endFrame = Math.min(startFrame + MAX_FRAMES_PER_SEGMENT, totalFrames);
            
            int startByte = startFrame * frameSize;
            int endByte = Math.min(endFrame * frameSize, pcmData.length);
            
            byte[] segment = Arrays.copyOfRange(pcmData, startByte, endByte);
            System.out.println("处理第 " + (i + 1) + "/" + segments + " 段音频，帧数: " + (endFrame - startFrame));
            
            String segmentResult = processSingleAudioSegment(segment);
            
            if (segmentResult != null && !segmentResult.trim().isEmpty()) {
                if (lastSegmentResult != null) {
                    // 处理重叠部分
                    int overlapIndex = findOverlapIndex(lastSegmentResult, segmentResult);
                    if (overlapIndex > 0) {
                        finalResult.append(segmentResult.substring(overlapIndex));
                    } else {
                        finalResult.append(" ").append(segmentResult);
                    }
                } else {
                    finalResult.append(segmentResult);
                }
                lastSegmentResult = segmentResult;
            }
            
            // 在段之间添加短暂延迟
            Thread.sleep(1000);
        }
        
        return finalResult.toString();
    }

    private int findOverlapIndex(String lastResult, String currentResult) {
        // 查找重叠部分，从后向前匹配
        int minLength = Math.min(lastResult.length(), currentResult.length());
        for (int i = minLength; i > 0; i--) {
            String lastSuffix = lastResult.substring(lastResult.length() - i);
            String currentPrefix = currentResult.substring(0, i);
            if (lastSuffix.equals(currentPrefix)) {
                return i;
            }
        }
        return 0;
    }

    private String processSingleAudioSegment(byte[] pcmData) throws UnsupportedEncodingException, InterruptedException {
        Map<String, String> queryParams = new HashMap<>();
        queryParams.put("client_version", "unknown");
        queryParams.put("package", "unknown");
        queryParams.put("user_id", generate32CharUserId());
        queryParams.put("sdk_version", "unknown");
        queryParams.put("android_version", "unknown");
        queryParams.put("system_time", String.valueOf(System.currentTimeMillis()));
        queryParams.put("net_type", "1");
        queryParams.put("engineid", "shortasrinput");

        String queryString = buildQueryString(queryParams);
        HttpHeaders headers = VivoAuth.generateAuthHeaders(APP_ID, APP_KEY, METHOD, URI_PATH, queryString);
        String url = buildWebSocketUrl(queryParams);

        AsrWebSocketClient client = new AsrWebSocketClient();
        client.setFanhui();
        
        int retryCount = 0;
        int maxRetries = 3;
        
        while (retryCount < maxRetries) {
            try {
                client.connect(url, headers);
                
                int frameSize = 1280; // 40毫秒帧长
                int totalFrames = (int) Math.ceil(pcmData.length / (double) frameSize);
                
                System.out.println("开始发送音频数据，总帧数: " + totalFrames);
                
                // 先发送一小段静音数据（20ms）
                byte[] silence = new byte[640]; // 20ms的静音
                client.sendAudio(silence);
                Thread.sleep(20);
                
                for (int i = 0; i < pcmData.length; i += frameSize) {
                    int end = Math.min(i + frameSize, pcmData.length);
                    byte[] frame = Arrays.copyOfRange(pcmData, i, end);
                    client.sendAudio(frame);
                    
                    Thread.sleep(40);
                    
                    if (i % (frameSize * 10) == 0) {
                        System.out.println("已发送 " + (i / frameSize) + "/" + totalFrames + " 帧");
                    }
                }
                
                client.sendAudio(silence);
                Thread.sleep(20);
                
                System.out.println("音频数据发送完成，发送结束标记");
                client.sendAudio("--end--".getBytes());
                
                int maxWaitTime = 15000;
                int interval = 100;
                for (int i = 0; i < maxWaitTime; i += interval) {
                    String result = client.getFanhui();
                    if (result != null && !result.trim().isEmpty()) {
                        System.out.println("收到最终识别结果: " + result);
                        return result;
                    }
                    Thread.sleep(interval);
                }
                
                throw new RuntimeException("识别超时");
            } catch (Exception e) {
                retryCount++;
                System.out.println("第" + retryCount + "次尝试失败: " + e.getMessage());
                if (retryCount >= maxRetries) {
                    throw new RuntimeException("ASR请求失败，已重试" + maxRetries + "次", e);
                }
                Thread.sleep(1000);
            } finally {
                try {
                    client.closeConnection();
                } catch (Exception e) {
                    System.out.println("关闭连接时出错: " + e.getMessage());
                }
            }
        }
        
        throw new RuntimeException("ASR请求失败");
    }

    private int calculateAudioDuration(byte[] pcmData) {
        // 计算音频时长（毫秒）
        return (int) ((pcmData.length * 1000L) / BYTES_PER_SECOND);
    }

    private String buildQueryString(Map<String, String> params) {
        return params.entrySet().stream()
                .map(entry -> entry.getKey() + "=" + URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8))
                .collect(Collectors.joining("&"));
    }

    private String buildWebSocketUrl(Map<String, String> params) {
        return "wss://api-ai.vivo.com.cn/asr/v2?" + params.entrySet().stream()
                .map(e -> e.getKey() + "=" + URLEncoder.encode(e.getValue(), StandardCharsets.UTF_8))
                .collect(Collectors.joining("&"));
    }

    // 生成32位用户ID（小写字母+数字）
    private String generate32CharUserId() {
        return UUID.randomUUID().toString().replace("-", "").substring(0, 32);
    }
}